package cn.wgx.modules.base.web;

import cn.wgx.commons.annotation.ApiPermission;
import cn.wgx.commons.storage.FastDFSClient;
import cn.wgx.commons.storage.fastdfs.domain.StorePath;
import cn.wgx.commons.util.DateUtils;
import cn.wgx.commons.util.MD5;
import cn.wgx.commons.util.StringUtils;
import cn.wgx.modules.sys.entity.SysRes;
import cn.wgx.modules.sys.services.SysResService;
import cn.wgx.modules.sys.util.ResUtil;
import com.baidu.ueditor.ActionEnter;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Map;
import java.util.UUID;


@Api(description = "公共文件上传入口")
@RestController
@RequestMapping(value = "api/fileupload")
public class UploadFileController extends BaseController {


    @Value("${upload.folder}")
    public String UPLOAD_FOLDER;

    private String CONTEXTURL;

    @ApiOperation("获取文件服务器地址")
    @RequestMapping(value = "getserver", method = RequestMethod.GET)
    public Map<String, Object> getFileServer(){
        return returnData(FastDFSClient.getFileWebServerUrl());
    }


    @ApiOperation(value = "检测MD5", notes = "发送上传文件的MD5值,如果服务器有则直接返回结果")
    @ApiPermission(value = false)
    @RequestMapping(value = "getByMD5", method = RequestMethod.GET)
    public Map<String, Object> getFileMd5(String md5,
                                          @RequestParam(required = false, defaultValue = "false") boolean thumbnail,
                                          @RequestParam(required = false, defaultValue = "300") Integer width,
                                          @RequestParam(required = false, defaultValue = "300") Integer height){
        SysRes oneByMD5 = ResUtil.getByMD5(md5);
        if(oneByMD5 == null){
            return returnErrorMap("no");
        }
        Map<String, Object> map = getInitMap();
        if(thumbnail){
            //缩略图MD5值
            String thumbnail_md5 = "thumbnail-"+width+"*"+height+"-"+md5;
            SysRes s = ResUtil.getByMD5(thumbnail_md5);
            if(s == null){
                String fastdfsImgthumbnail = FastDFSClient.getFastdfsImgthumbnail(oneByMD5.getUrl(), thumbnail_md5, width, height);
                map.put("thumbnail", fastdfsImgthumbnail);
            }else{
                map.put("thumbnail", s.getUrl());
            }
        }
        map.put("data", oneByMD5.getUrl());
        map.put("server", FastDFSClient.getFileWebServerUrl());
        map.put("link",  FastDFSClient.getFileWebServerUrl() + oneByMD5.getUrl());
        map.put("res_id", oneByMD5.getResource_id());
        return map;
    }


    @ApiOperation(value = "上传图片至fastdfs并产生缩略图", notes = "必须参数:md5. 可选参数:thumbnail(是否需要缩略图),width(缩略图宽),height(缩略图高)." +
            "返回res:相对地址.  缩略图最终是等比的.")
    @ApiPermission(value = false)
    @RequestMapping(value = "addImg", method = RequestMethod.POST)
    public Map<String, Object> addImg(MultipartFile attach,
                                      @RequestParam() String md5,
                                      @RequestParam(required = false, defaultValue = "false") boolean thumbnail,
                                      @RequestParam(required = false, defaultValue = "300") Integer width,
                                      @RequestParam(required = false, defaultValue = "300") Integer height,
                                      HttpServletRequest request)
            throws IOException {
//        if(StringUtils.isBlank(md5) || md5.length() < 30){
//            return returnErrorMap("MD5错误(>30位)");
//        }
        //上传附带MD5值
        if(StringUtils.isBlank(md5)){
            String originalFilename = attach.getOriginalFilename();
            long size = attach.getSize();
            String s = MD5.MD5(originalFilename + size);
            md5 = s;
        }
        //缩略图MD5值
        String thumbnail_md5 = "thumbnail-"+width+"*"+height+"-"+md5;
        //先根据MD5判断是否已上传
        SysRes oneByMD5 = ResUtil.getByMD5(md5);
        if(oneByMD5 != null){
            Map<String, Object> map = getInitMap();
            if(thumbnail){
                SysRes s = ResUtil.getByMD5(thumbnail_md5);
                if(s == null){
                    String fastdfsImgthumbnail = FastDFSClient.getFastdfsImgthumbnail(oneByMD5.getUrl(), thumbnail_md5, width, height);
                    map.put("thumbnail", fastdfsImgthumbnail);
                }else{
                    map.put("thumbnail", s.getUrl());
                }
            }
            map.put("data", oneByMD5.getUrl());
            map.put("server", FastDFSClient.getFileWebServerUrl());
            map.put("link",  FastDFSClient.getFileWebServerUrl() + oneByMD5.getUrl());
            map.put("res_id", oneByMD5.getResource_id());
            return map;
        }

        Map<String, Object> map = getInitMap();
        //上传文件至fastdfs
        String filePath = FastDFSClient.uploadFile(attach);
        //如果需要缩略图
        if(thumbnail){
            //生成缩略图并上传并保存数据库
            String fastdfsImgthumbnail = FastDFSClient.getFastdfsImgthumbnail(filePath, thumbnail_md5, width, height);
            map.put("thumbnail", fastdfsImgthumbnail);
        }

        //保存文件 插入数据库记录
        ResUtil.save(attach, filePath, "fdfs", md5, request);

        map.put("data", filePath);
        map.put("server", FastDFSClient.getFileWebServerUrl());
        map.put("link",  FastDFSClient.getFileWebServerUrl() + filePath);
        return map;
    }


    @ApiOperation(value = "上传文件服务器fastdfs", notes = "必须参数:md5. 返回res:相对地址;resResource:文件对象")
    @ApiPermission(value = false)
    @RequestMapping(value = "add", method = RequestMethod.POST)
    public Map<String, Object> add(MultipartFile attach, @RequestParam(required = false) String md5,HttpServletRequest request)
            throws IOException {
//        if(StringUtils.isBlank(md5) || md5.length() < 30){
//            return returnErrorMap("MD5错误(>30位)");
//        }
        //上传附带MD5值
        if(StringUtils.isBlank(md5)){
            String originalFilename = attach.getOriginalFilename();
            long size = attach.getSize();
            String s = MD5.MD5(originalFilename + size);
            md5 = s;
        }
        //先根据MD5判断是否已上传
        SysRes oneByMD5 = ResUtil.getByMD5(md5);
        if(oneByMD5 != null){
            Map<String, Object> map = getInitMap();
            map.put("data", oneByMD5.getUrl());
            map.put("server", FastDFSClient.getFileWebServerUrl());
            map.put("link",  FastDFSClient.getFileWebServerUrl() + oneByMD5.getUrl());
            map.put("res_id", oneByMD5.getResource_id());
            return map;
        }

        Map<String, Object> map = getInitMap();
        //上传至fastdfs
        String filePath = FastDFSClient.uploadFile(attach);

        //保存文件 插入数据库记录
        ResUtil.save(attach, filePath, "fdfs", md5, request);

        map.put("data", filePath);
        map.put("server", FastDFSClient.getFileWebServerUrl());
        map.put("link",  FastDFSClient.getFileWebServerUrl() + filePath);
        return map;
    }


    @ApiOperation(value = "fastdfs分片上传", notes = "必须参数:md5,allSize(总字节数),offSet(偏移量),fileName(原始文件名),size(总文件大小) 返回res:相对地址;resResource:文件对象")
    @ApiPermission(value = false)
    @RequestMapping(value = "addAppend", method = RequestMethod.POST)
    public Map<String, Object> append(MultipartFile attach,
                                      @RequestParam() String md5,
                                      @RequestParam() Long allSize,
                                      @RequestParam() Long offSet,
                                      @RequestParam() String fileName,
                                      HttpServletRequest request)
            throws IOException {
//        if(StringUtils.isBlank(md5) || md5.length() < 30){
//            return returnErrorMap("MD5错误(>30位)");
//        }
        //上传附带MD5值
        if(StringUtils.isBlank(md5)){
            return  returnErrorMap("MD5不能为空");
        }
        if(offSet == 0){
            //先根据MD5判断是否已上传
            SysRes oneByMD5 = ResUtil.getByMD5(md5);
            if(oneByMD5 != null){
                Map<String, Object> map = getInitMap();
                map.put("data", oneByMD5.getUrl());
                map.put("server", FastDFSClient.getFileWebServerUrl());
                map.put("link",  FastDFSClient.getFileWebServerUrl() + oneByMD5.getUrl());
                map.put("res_id", oneByMD5.getResource_id());
                map.put("cache", true);
                return map;
            }
        }
        Map<String, Object> map = getInitMap();
        //上传至fastdfs
        StorePath filePath = FastDFSClient.uploadFileAppend(attach, md5, allSize, offSet, fileName);
        if(filePath == null){
            return  returnErrorMap("上传错误.");
        }
        if(allSize == (filePath.getSuccessOffset())){//全部上传完成则插入数据库
            //保存文件 插入数据库记录
            ResUtil.save(fileName, allSize, filePath.getFullPath(), "fdfs", md5, request);
        }

        map.put("data", filePath.getFullPath());
        map.put("server", FastDFSClient.getFileWebServerUrl());
        map.put("link",  FastDFSClient.getFileWebServerUrl() + filePath.getFullPath());
        map.put("offSet",  filePath.getSuccessOffset());
        return map;
    }
    @ApiOperation(value = "获取fastdfs token", notes = "")
    @ApiPermission(value = false)
    @RequestMapping(value = "getFastToken", method = RequestMethod.POST)
    public Map<String, Object> getFastdfsToken(){
//        String fid="group2/M00/00/02/wKjgzFrpTGOAUl37AABFbiLVDsI531.png";
//        String substring = fid.substring(fid.indexOf("/")+1);
//        int ts = (int) (System.currentTimeMillis() / 1000);
//        String secret_key = "FastDFS1234567890";
//        String token=new String();
//        try {
//            token= ProtoCommon.getToken(substring, ts, secret_key);
//        } catch (UnsupportedEncodingException e) {
//            e.printStackTrace();
//        }
        return returnData("");
    }

    @ApiOperation(value = "报告服务器已使用的url", notes = "必须参数: url. 告知服务器此url已被使用,防止无效文件存储")
    @ApiPermission(value = false)
    @RequestMapping(value = "updateUsed", method = RequestMethod.PATCH)
    public Map<String, Object> update(@RequestBody SysRes sysRes) {
        if(sysRes== null || StringUtils.isBlank(sysRes.getUrl())){
            return returnErrorMap("参数错误: url");
        }
        return returnData(ResUtil.updateUserByUrl(sysRes.getUrl()));
    }


    @ApiOperation(value = "百度编辑器上传文件接口", notes = "将ueditor.config.js内的\"jsp/controller.jsp\" 改为 \"../api/fileupload/ueditor\"" )
    @ApiPermission(value = false)
//    @RequestMapping(value = "ueditor", method = {RequestMethod.GET, RequestMethod.POST})
    public Map<String, Object> uploadFileByBaidu(@RequestParam(required = false, defaultValue = "config") String action,
                                                 HttpServletRequest request, HttpServletResponse response) {
        try {
            request.setCharacterEncoding( "utf-8" );
//            response.setHeader("Content-Type" , "application/json");
            response.setHeader("Content-Type" , "text/html");
            response.setCharacterEncoding("utf-8");
            String rootPath = request.getServletContext().getRealPath( "/" );
            response.getWriter().write( new ActionEnter( request, rootPath, "WEB-INF/classes/config.json").exec() );
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    @ApiOperation("上传文件至项目路径下,图片类型上传,上传完毕返回[相对URL]路径")
    @ApiPermission(value = false)
//    @PostMapping(value = "img")
    public Map<String, Object> uploadFile(MultipartFile file, HttpServletRequest request, HttpSession session) {

        Map<String, Object> map = getInitMap();
        if (!file.isEmpty()) {
            try {
                String s = doUploadFile(file);
                if (null == CONTEXTURL) {
                    CONTEXTURL = request.getScheme() + "://" + request.getServerName()
                            + (request.getServerPort()==80?"":":"+request.getServerPort()) + "/"
                            + (request.getContextPath().equals("")?"":request.getContextPath()+"/");
                }
                map.put("url", s);
                map.put("full-url", CONTEXTURL + s);
            } catch (IOException e) {
                returnErrorMap(e.getMessage(),map);
            }
        }
        return map;
    }


    private String doUploadFile(MultipartFile file) throws IOException {
        String fileName = file.getOriginalFilename();
        //文件随机起名字
        String uuidName = DateUtils.formatDate(new Date(), "yyyyMMddHHmmss") + "-" + UUID.randomUUID().toString().substring(0,13) + "." + fileName.substring(fileName.lastIndexOf(".") + 1);
        //建立当日日期文件夹
        String dayPath = DateUtils.formatDate(new Date(), "yyyyMMdd");
        //磁盘绝对路径
        String absolutePath = UPLOAD_FOLDER + dayPath;
        File file1 = new File(absolutePath);
        if(!file1.exists()){
            file1.mkdirs();
        }
        File destFile = new File(absolutePath, uuidName);
        file.transferTo(destFile);
        String path = "/" + dayPath + "/" + uuidName;
        return path;
    }

    //上传文件随机生成一个目录
    private String radomFolder(String fullPath, String str) {
//        if (!isRadomFolder) {
//            return "";
//        }
        int hascode = str.hashCode();
        String hex = Integer.toHexString(hascode);

        String ss = hex.charAt(0) + "/";

        File f = new File(fullPath + ss);
        if (!f.exists()) {
            f.mkdirs();
        }
//        int c1 = hascode & 0xf;
//        int c2 = hascode & 0xf0 >> 4;
//        System.out.println("hascode: " + hascode);
//        System.out.println("ss: " + ss);
//        System.out.println(c1);
//        System.out.println(c2);
        return ss;
    }

    @PostConstruct
    public void init() {
        //
        // FOLDER_PREFIX = this.getClass().getClassLoader().getResource("").getPath() + "../";
//        FULL_PATH = FOLDER_PREFIX + UPLOAD_FOLDER;
        File f = new File(UPLOAD_FOLDER);
        if (!f.exists()) {
            f.mkdirs();
        }
    }
}
